Q4. cから元のsudokuのフォーマットでsudoku_1を作ってください。また、これまでの解答から、ナンバープレースの問題を解いてください
from 第44回 シェル芸勉強会振り返り 問題と解答
#Q&A #awk #bash
cから元のsudokuのフォーマットでsudoku_1を作ってください。また、これまでの解答から、ナンバープレースの問題を解いてください
前の問題: Q3. 前の問題で作ったbから、次のように、入る数字の候補を5列目以降に書き込んだファイルcを作ってください
code:bash
$ cat sudoku_1
53**7****
6**195***
*98****6*
8***6***3
4**853**1
7***2***6
*6***7284
***419*35
****8**79
これは一応解けた
といっても置換する部分だけ
ナンバープレースの問題を解くのは、その前までのシェルを控えてなかったので諦めた
code:sed.sh
cat ShellGeiData/vol.44/c | sed -E "s/(^\*+)\* (0-9)$/\1\2/g" | awk '{print $4}' | tr -d \\n | grep -o .........
#シェル芸
*が出現する位置までを正規表現のグループにまとめる
それ以降の文字が数字1つだけなら、後方参照で結合して*を消す
というアプローチ
最後にgrepで9列ずつにばらした
以後は振り返り
最後に一連の処理を繰り返せばsudokuのデータは解ける
入力はsudokuの9x9のデータ、最後のシェルで9x9のデータに戻している
ここまでの一連のシェルは以下
Q1. 以下のナンバープレースを次のように、第一フィールドが行番号、第二フィールドが列番号、第三フィールドが区画(3x3のグリッドに適当に番号をつけたもの)、第四フィールドが値のファイルaに変換してください
Q2. 前の問題で作ったaから、次のように5列目以降に入らない数字を書き込んだファイルbを作ってください。入らない数字は重複を除去しなくて構いません
Q3. 前の問題で作ったbから、次のように、入る数字の候補を5列目以降に書き込んだファイルcを作ってください
これらを1つにまとめると以下
code:sudoku.sh
awk -v FS='' '{ for (i=0; i<NF; i++) { print NR-1, i, int((NR-1)/3)*3+int(i/3), $(i+1)} }' sudoku > a; cat a | while read -r a b c d; do echo -n "$a $b $c $d "; awk -v a=$a -v b=$b -v c=$c -v d=$d 'd == "*" && ($1==a || $2==b || $3==c) && $4!="*" {print $4}' a | sed -E "s/$/ /" | tr -d \\n; echo; done | sed -E "s/ $//g" | awk '4<NF{ printf "%s %s %s %s", $1, $2, $3, $4; for (i=1;i<10;i++) {numsi=0} for (i=5; i<=NF; i++) { nums$i=1 } for (k in nums) { if (numsk != 1) printf " %s", k } printf "\n" } NF<=4{print}' | sed -E "s/(^\*+)\* (0-9)$/\1\2/g" | awk '{print $4}' | tr -d \\n | grep -o .........
やばい
とりあえず、sudokuをバックアップして、ループで回してみる
パイプ元のデータをリダイレクトで上書きするとデータが失われるはずなので一時ファイルに吐いてからが良いと思う
code:bash
for __ in {1..10}; do
awk -v FS='' '{ for (i=0; i<NF; i++) { print NR-1, i, int((NR-1)/3)*3+int(i/3), $(i+1)} }' sudoku > a; cat a | while read -r a b c d; do echo -n "$a $b $c $d "; awk -v a=$a -v b=$b -v c=$c -v d=$d 'd == "*" && ($1==a || $2==b || $3==c) && $4!="*" {print $4}' a | sed -E "s/$/ /" | tr -d \\n; echo; done | sed -E "s/ $//g" | awk '4<NF{ printf "%s %s %s %s", $1, $2, $3, $4; for (i=1;i<10;i++) {numsi=0} for (i=5; i<=NF; i++) { nums$i=1 } for (k in nums) { if (numsk != 1) printf " %s", k } printf "\n" } NF<=4{print}' | sed -E "s/(^\*+)\* (0-9)$/\1\2/g" | awk '{print $4}' | tr -d \\n | grep -o ......... > sudoku.tmp
mv sudoku.tmp sudoku
done
きちんと分解すると以下
code:sudoku3.sh
for __ in {1..10}; do
awk -v FS='' '{ for (i=0; i<NF; i++) { print NR-1, i, int((NR-1)/3)*3+int(i/3), $(i+1)} }' sudoku > a
cat a | while read -r a b c d; do
echo -n "$a $b $c $d "
awk -v a=$a -v b=$b -v c=$c -v d=$d \
'd == "*" && ($1==a || $2==b || $3==c) && $4!="*" {print $4}' a |
sed -E "s/$/ /" |
tr -d \\n
echo
done |
sed -E "s/ $//g" |
awk '4<NF{ printf "%s %s %s %s", $1, $2, $3, $4; for (i=1;i<10;i++) {numsi=0} for (i=5; i<=NF; i++) { nums$i=1 } for (k in nums) { if (numsk != 1) printf " %s", k } printf "\n" } NF<=4{print}' | sed -E "s/(^\*+)\* (0-9)$/\1\2/g" |
awk '{print $4}' |
tr -d \\n |
grep -o ......... > sudoku.tmp
mv sudoku.tmp sudoku
done
なんだこれは
とはいえ、無事問題を自力で解けた
じっくり時間をかければきちんと解ける問題だと分かって良かった
一応書く時は他の方の解答とかは見ずにやった